{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "93391df2-a94c-4086-85f3-d57f9dacd116",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Turtle object at 0x00000155031CCDD0>\n",
      "<class '__main__.Turtle'>\n",
      "<class '__main__.Turtle'>\n",
      "Turtle\n",
      "我正在很努力的向前爬...\n",
      "我正在飞快的向前跑...\n",
      "咬死你咬死你!!\n",
      "<class 'type'>\n"
     ]
    }
   ],
   "source": [
    "class Turtle:  # Python中的类名约定以大写字母开头\n",
    "    \"\"\"关于类的一个简单例子\"\"\"\n",
    "    # 属性\n",
    "    color = 'green'\n",
    "    weight = 10\n",
    "    legs = 4\n",
    "    shell = True\n",
    "    mouth = '大嘴'\n",
    "\n",
    "    # 方法\n",
    "    def climb(self):\n",
    "        print('我正在很努力的向前爬...')\n",
    "\n",
    "    def run(self):\n",
    "        print('我正在飞快的向前跑...')\n",
    "\n",
    "    def bite(self):\n",
    "        print('咬死你咬死你!!')\n",
    "\n",
    "    def eat(self):\n",
    "        print('有得吃，真满足...')\n",
    "\n",
    "    def sleep(self):\n",
    "        print('困了，睡了，晚安，zzz')\n",
    "\n",
    "\n",
    "tt = Turtle()\n",
    "print(tt)\n",
    "# <__main__.Turtle object at 0x0000007C32D67F98>\n",
    "\n",
    "print(type(tt))\n",
    "# <class '__main__.Turtle'>\n",
    "\n",
    "print(tt.__class__)\n",
    "# <class '__main__.Turtle'>\n",
    "\n",
    "print(tt.__class__.__name__)\n",
    "# Turtle\n",
    "\n",
    "tt.climb()\n",
    "# 我正在很努力的向前爬...\n",
    "\n",
    "tt.run()\n",
    "# 我正在飞快的向前跑...\n",
    "\n",
    "tt.bite()\n",
    "# 咬死你咬死你!!\n",
    "\n",
    "# Python类也是对象。它们是type的实例\n",
    "print(type(Turtle))\n",
    "# <class 'type'>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "c95f07bc-8377-4ee2-9446-bf65c9683e2f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 5, 7, 8, 9]\n"
     ]
    }
   ],
   "source": [
    "class MyList(list):\n",
    "    pass\n",
    "\n",
    "\n",
    "lst = MyList([1, 5, 2, 7, 8])\n",
    "lst.append(9)\n",
    "lst.sort()\n",
    "print(lst)\n",
    "\n",
    "# [1, 2, 5, 7, 8, 9]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "670a6922-9a9f-4ac7-a465-1ff0db6fc0a5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pig is walking\n"
     ]
    }
   ],
   "source": [
    "class Animal:\n",
    "    def run(self):\n",
    "        raise AttributeError('子类必须实现这个方法')\n",
    "\n",
    "\n",
    "class People(Animal):\n",
    "    def run(self):\n",
    "        print('人正在走')\n",
    "\n",
    "\n",
    "class Pig(Animal):\n",
    "    def run(self):\n",
    "        print('pig is walking')\n",
    "\n",
    "\n",
    "class Dog(Animal):\n",
    "    def run(self):\n",
    "        print('dog is running')\n",
    "\n",
    "\n",
    "def func(animal):\n",
    "    animal.run()\n",
    "\n",
    "\n",
    "func(Pig())\n",
    "# pig is walking"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "d4e00473-1761-46f3-9b34-a89d495b24ca",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<__main__.Test object at 0x0000015504647CB0>\n",
      "<class '__main__.Test'>\n"
     ]
    }
   ],
   "source": [
    "class Test:\n",
    "    def prt(self):\n",
    "        print(self)\n",
    "        print(self.__class__)\n",
    "\n",
    "t = Test()\n",
    "t.prt()\n",
    "# <__main__.Test object at 0x000000BC5A351208>\n",
    "# <class '__main__.Test'>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d710dde-603b-4762-a345-5fc91a697104",
   "metadata": {},
   "source": [
    "类的方法与普通的函数只有一个特别的区别 —— 它们必须有一个额外的第一个参数名称（对应于该实例，即该对象本身），\n",
    "按照惯例它的名称是 self。在调用方法时，我们无需明确提供与参数 self 相对应的参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "6bbb2d2b-32a0-4906-9898-cbe3727a8fad",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我叫球A,该死的，谁踢我...\n",
      "我叫球B,该死的，谁踢我...\n"
     ]
    }
   ],
   "source": [
    "class Ball:\n",
    "    def setName(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def kick(self):\n",
    "        print(\"我叫%s,该死的，谁踢我...\" % self.name)\n",
    "\n",
    "\n",
    "a = Ball()\n",
    "a.setName(\"球A\")\n",
    "b = Ball()\n",
    "b.setName(\"球B\")\n",
    "a.kick()\n",
    "# 我叫球A,该死的，谁踢我...\n",
    "b.kick()\n",
    "# 我叫球B,该死的，谁踢我..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "ed8a6405-d8ea-4a57-9337-5c761d05ae4c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我叫球A,该死的，谁踢我...\n",
      "我叫球B,该死的，谁踢我...\n"
     ]
    }
   ],
   "source": [
    "class Ball:\n",
    "    def __init__(self, name):\n",
    "        self.name = name\n",
    "\n",
    "    def kick(self):\n",
    "        print(\"我叫%s,该死的，谁踢我...\" % self.name)\n",
    "\n",
    "\n",
    "a = Ball(\"球A\")\n",
    "b = Ball(\"球B\")\n",
    "c = Ball(\"球C\")\n",
    "a.kick()\n",
    "# 我叫球A,该死的，谁踢我...\n",
    "b.kick()\n",
    "# 我叫球B,该死的，谁踢我..."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7285b0b0-859c-4112-adbe-4925b33d8713",
   "metadata": {},
   "source": [
    "在 Python 中定义私有变量只需要在变量名或函数名前加上“__”两个下划线，那么这个函数或变量就会为私有的了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "5b94222e-6573-444d-bc5f-e2b189f981bf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "2\n",
      "2\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'JustCounter' object has no attribute '__secretCount'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[8], line 20\u001b[0m\n\u001b[0;32m     18\u001b[0m \u001b[38;5;66;03m# Python的私有为伪私有\u001b[39;00m\n\u001b[0;32m     19\u001b[0m \u001b[38;5;28mprint\u001b[39m(counter\u001b[38;5;241m.\u001b[39m_JustCounter__secretCount)  \u001b[38;5;66;03m# 2 \u001b[39;00m\n\u001b[1;32m---> 20\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mcounter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__secretCount\u001b[49m)  \n\u001b[0;32m     21\u001b[0m \u001b[38;5;66;03m# AttributeError: 'JustCounter' object has no attribute '__secretCount'\u001b[39;00m\n",
      "\u001b[1;31mAttributeError\u001b[0m: 'JustCounter' object has no attribute '__secretCount'"
     ]
    }
   ],
   "source": [
    "class JustCounter:\n",
    "    __secretCount = 0  # 私有变量\n",
    "    publicCount = 0  # 公开变量\n",
    "\n",
    "    def count(self):\n",
    "        self.__secretCount += 1\n",
    "        self.publicCount += 1\n",
    "        print(self.__secretCount)\n",
    "\n",
    "\n",
    "counter = JustCounter()\n",
    "counter.count()  # 1\n",
    "counter.count()  # 2\n",
    "print(counter.publicCount)  # 2\n",
    "\n",
    "# Python的私有为伪私有\n",
    "print(counter._JustCounter__secretCount)  # 2 \n",
    "print(counter.__secretCount)  \n",
    "# AttributeError: 'JustCounter' object has no attribute '__secretCount'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "45da82df-3420-46d8-aa10-bb46cc1b4293",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name  :  老马的程序人生\n",
      "url :  https://blog.csdn.net/LSGO_MYP\n",
      "这是公共方法\n",
      "这是私有方法\n",
      "这是私有方法\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'Site' object has no attribute '__foo'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[10], line 29\u001b[0m\n\u001b[0;32m     24\u001b[0m \u001b[38;5;66;03m# 这是公共方法\u001b[39;00m\n\u001b[0;32m     25\u001b[0m \u001b[38;5;66;03m# 这是私有方法\u001b[39;00m\n\u001b[0;32m     27\u001b[0m x\u001b[38;5;241m.\u001b[39m_Site__foo()\n\u001b[1;32m---> 29\u001b[0m \u001b[43mx\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__foo\u001b[49m()\n\u001b[0;32m     30\u001b[0m \u001b[38;5;66;03m# AttributeError: 'Site' object has no attribute '__foo'\u001b[39;00m\n",
      "\u001b[1;31mAttributeError\u001b[0m: 'Site' object has no attribute '__foo'"
     ]
    }
   ],
   "source": [
    "class Site:\n",
    "    def __init__(self, name, url):\n",
    "        self.name = name  # public\n",
    "        self.__url = url  # private\n",
    "\n",
    "    def who(self):\n",
    "        print('name  : ', self.name)\n",
    "        print('url : ', self.__url)\n",
    "\n",
    "    def __foo(self):  # 私有方法\n",
    "        print('这是私有方法')\n",
    "\n",
    "    def foo(self):  # 公共方法\n",
    "        print('这是公共方法')\n",
    "        self.__foo()\n",
    "\n",
    "\n",
    "x = Site('老马的程序人生', 'https://blog.csdn.net/LSGO_MYP')\n",
    "x.who()\n",
    "# name  :  老马的程序人生\n",
    "# url :  https://blog.csdn.net/LSGO_MYP\n",
    "\n",
    "x.foo()\n",
    "# 这是公共方法\n",
    "# 这是私有方法\n",
    "\n",
    "x._Site__foo()\n",
    "\n",
    "x.__foo()\n",
    "# AttributeError: 'Site' object has no attribute '__foo'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "fd343c91-260a-4db1-b823-5d00396ee453",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "小马的程序人生 说: 我 10 岁了，我在读 3 年级\n"
     ]
    }
   ],
   "source": [
    "# 类定义\n",
    "class people:\n",
    "    # 定义基本属性\n",
    "    name = ''\n",
    "    age = 0\n",
    "    # 定义私有属性,私有属性在类外部无法直接进行访问\n",
    "    __weight = 0\n",
    "\n",
    "    # 定义构造方法\n",
    "    def __init__(self, n, a, w):\n",
    "        self.name = n\n",
    "        self.age = a\n",
    "        self.__weight = w\n",
    "\n",
    "    def speak(self):\n",
    "        print(\"%s 说: 我 %d 岁。\" % (self.name, self.age))\n",
    "\n",
    "\n",
    "# 单继承示例\n",
    "class student(people):\n",
    "    grade = ''\n",
    "\n",
    "    def __init__(self, n, a, w, g):\n",
    "        # 调用父类的构函\n",
    "        people.__init__(self, n, a, w)\n",
    "        self.grade = g\n",
    "\n",
    "    # 覆写父类的方法\n",
    "    def speak(self):\n",
    "        print(\"%s 说: 我 %d 岁了，我在读 %d 年级\" % (self.name, self.age, self.grade))\n",
    "\n",
    "\n",
    "s = student('小马的程序人生', 10, 60, 3)\n",
    "s.speak()\n",
    "# 小马的程序人生 说: 我 10 岁了，我在读 3 年级"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "3ef5dba2-66a1-48bd-8a62-97a498227723",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我的位置 4 3\n",
      "吃货的梦想就是天天有得吃！\n",
      "我的位置 8 3\n"
     ]
    }
   ],
   "source": [
    "# 通过 super().__init__() 初始化\n",
    "\n",
    "import random\n",
    "\n",
    "class Fish:\n",
    "    def __init__(self):\n",
    "        self.x = random.randint(0, 10)\n",
    "        self.y = random.randint(0, 10)\n",
    "\n",
    "    def move(self):\n",
    "        self.x -= 1\n",
    "        print(\"我的位置\", self.x, self.y)\n",
    "\n",
    "\n",
    "class GoldFish(Fish):  # 金鱼\n",
    "    pass\n",
    "\n",
    "\n",
    "class Carp(Fish):  # 鲤鱼\n",
    "    pass\n",
    "\n",
    "\n",
    "class Salmon(Fish):  # 三文鱼\n",
    "    pass\n",
    "\n",
    "\n",
    "class Shark(Fish):  # 鲨鱼\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.hungry = True\n",
    "\n",
    "    def eat(self):\n",
    "        if self.hungry:\n",
    "            print(\"吃货的梦想就是天天有得吃！\")\n",
    "            self.hungry = False\n",
    "        else:\n",
    "            print(\"太撑了，吃不下了！\")\n",
    "            self.hungry = True\n",
    "\n",
    "\n",
    "g = GoldFish()\n",
    "g.move()  # 我的位置 9 4\n",
    "s = Shark()\n",
    "s.eat() # 吃货的梦想就是天天有得吃！\n",
    "s.move()  \n",
    "# AttributeError: 'Shark' object has no attribute 'x'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "10e81e35-e12a-41be-a834-686395a76fed",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我叫 Tim，我是一个演说家，我演讲的主题是 Python\n",
      "Tim 说: 我 25 岁了，我在读 4 年级\n"
     ]
    }
   ],
   "source": [
    "# 类定义\n",
    "class People:\n",
    "    # 定义基本属性\n",
    "    name = ''\n",
    "    age = 0\n",
    "    # 定义私有属性,私有属性在类外部无法直接进行访问\n",
    "    __weight = 0\n",
    "\n",
    "    # 定义构造方法\n",
    "    def __init__(self, n, a, w):\n",
    "        self.name = n\n",
    "        self.age = a\n",
    "        self.__weight = w\n",
    "\n",
    "    def speak(self):\n",
    "        print(\"%s 说: 我 %d 岁。\" % (self.name, self.age))\n",
    "\n",
    "\n",
    "# 单继承示例\n",
    "class Student(People):\n",
    "    grade = ''\n",
    "\n",
    "    def __init__(self, n, a, w, g):\n",
    "        # 调用父类的构函\n",
    "        People.__init__(self, n, a, w)\n",
    "        self.grade = g\n",
    "\n",
    "    # 覆写父类的方法\n",
    "    def speak(self):\n",
    "        print(\"%s 说: 我 %d 岁了，我在读 %d 年级\" % (self.name, self.age, self.grade))\n",
    "\n",
    "\n",
    "# 另一个类，多重继承之前的准备\n",
    "class Speaker:\n",
    "    topic = ''\n",
    "    name = ''\n",
    "\n",
    "    def __init__(self, n, t):\n",
    "        self.name = n\n",
    "        self.topic = t\n",
    "\n",
    "    def speak(self):\n",
    "        print(\"我叫 %s，我是一个演说家，我演讲的主题是 %s\" % (self.name, self.topic))\n",
    "\n",
    "\n",
    "# 多重继承\n",
    "class Sample01(Speaker, Student):\n",
    "    a = ''\n",
    "\n",
    "    def __init__(self, n, a, w, g, t):\n",
    "        Student.__init__(self, n, a, w, g)\n",
    "        Speaker.__init__(self, n, t)\n",
    "\n",
    "# 方法名同，默认调用的是在括号中排前地父类的方法\n",
    "test = Sample01(\"Tim\", 25, 80, 4, \"Python\")\n",
    "test.speak()  \n",
    "# 我叫 Tim，我是一个演说家，我演讲的主题是 Python\n",
    "\n",
    "class Sample02(Student, Speaker):\n",
    "    a = ''\n",
    "\n",
    "    def __init__(self, n, a, w, g, t):\n",
    "        Student.__init__(self, n, a, w, g)\n",
    "        Speaker.__init__(self, n, t)\n",
    "\n",
    "# 方法名同，默认调用的是在括号中排前地父类的方法\n",
    "test = Sample02(\"Tim\", 25, 80, 4, \"Python\")\n",
    "test.speak()  \n",
    "# Tim 说: 我 25 岁了，我在读 4 年级"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "86fe6dd0-6f4d-4e37-bd83-dc2af7e83466",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "水池里面有乌龟2只，小鱼3条\n"
     ]
    }
   ],
   "source": [
    "class Turtle:\n",
    "    def __init__(self, x):\n",
    "        self.num = x\n",
    "\n",
    "\n",
    "class Fish:\n",
    "    def __init__(self, x):\n",
    "        self.num = x\n",
    "\n",
    "\n",
    "class Pool:\n",
    "    def __init__(self, x, y):\n",
    "        self.turtle = Turtle(x)\n",
    "        self.fish = Fish(y)\n",
    "\n",
    "    def print_num(self):\n",
    "        print(\"水池里面有乌龟%s只，小鱼%s条\" % (self.turtle.num, self.fish.num))\n",
    "\n",
    "\n",
    "p = Pool(2, 3)\n",
    "p.print_num()\n",
    "# 水池里面有乌龟2只，小鱼3条"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2e9147b2-8550-4de5-803b-a3304fc7f3d6",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建类对象\n",
    "class Test(object):\n",
    "    class_attr = 100  # 类属性\n",
    "\n",
    "    def __init__(self):\n",
    "        self.sl_attr = 100  # 实例属性\n",
    "\n",
    "    def func(self):\n",
    "        print('类对象.类属性的值:', Test.class_attr)  # 调用类属性\n",
    "        print('self.类属性的值', self.class_attr)  # 相当于把类属性 变成实例属性\n",
    "        print('self.实例属性的值', self.sl_attr)  # 调用实例属性\n",
    "\n",
    "\n",
    "a = Test()\n",
    "a.func()\n",
    "\n",
    "# 类对象.类属性的值: 100\n",
    "# self.类属性的值 100\n",
    "# self.实例属性的值 100\n",
    "\n",
    "b = Test()\n",
    "b.func()\n",
    "\n",
    "# 类对象.类属性的值: 100\n",
    "# self.类属性的值 100\n",
    "# self.实例属性的值 100\n",
    "\n",
    "a.class_attr = 200\n",
    "a.sl_attr = 200\n",
    "a.func()\n",
    "\n",
    "# 类对象.类属性的值: 100\n",
    "# self.类属性的值 200\n",
    "# self.实例属性的值 200\n",
    "\n",
    "b.func()\n",
    "\n",
    "# 类对象.类属性的值: 100\n",
    "# self.类属性的值 100\n",
    "# self.实例属性的值 100\n",
    "\n",
    "Test.class_attr = 300\n",
    "a.func()\n",
    "\n",
    "# 类对象.类属性的值: 300\n",
    "# self.类属性的值 200\n",
    "# self.实例属性的值 200\n",
    "\n",
    "b.func()\n",
    "# 类对象.类属性的值: 300\n",
    "# self.类属性的值 300\n",
    "# self.实例属性的值 100"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "7d16c74f-1199-47ee-8d95-8221199f9735",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x_man\n",
      "1\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "'int' object is not callable",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[18], line 10\u001b[0m\n\u001b[0;32m      8\u001b[0m aa\u001b[38;5;241m.\u001b[39mx \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m      9\u001b[0m \u001b[38;5;28mprint\u001b[39m(aa\u001b[38;5;241m.\u001b[39mx)  \u001b[38;5;66;03m# 1\u001b[39;00m\n\u001b[1;32m---> 10\u001b[0m \u001b[43maa\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mx\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m     11\u001b[0m \u001b[38;5;66;03m# TypeError: 'int' object is not callable\u001b[39;00m\n",
      "\u001b[1;31mTypeError\u001b[0m: 'int' object is not callable"
     ]
    }
   ],
   "source": [
    "class A:\n",
    "    def x(self):\n",
    "        print('x_man')\n",
    "\n",
    "\n",
    "aa = A()\n",
    "aa.x()  # x_man\n",
    "aa.x = 1\n",
    "print(aa.x)  # 1\n",
    "aa.x()\n",
    "# TypeError: 'int' object is not callable "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b011f5d6-14d8-4e26-9d0d-b38adc0c3d3b",
   "metadata": {},
   "source": [
    "什么是绑定？\n",
    "Python 严格要求方法需要有实例才能被调用，这种限制其实就是 Python 所谓的绑定概念。\n",
    "\n",
    "Python 对象的数据属性通常存储在名为.__ dict__的字典中，我们可以直接访问__dict__，或利用 Python 的内置函数vars()获取.__ dict__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "0506ad1f-6dfe-4bb5-8c97-80d91751e297",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{}\n",
      "{}\n",
      "{'__module__': '__main__', 'setXY': <function CC.setXY at 0x0000015504CCACA0>, 'printXY': <function CC.printXY at 0x0000015504CCAC00>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}\n",
      "{'x': 4, 'y': 5}\n",
      "{'x': 4, 'y': 5}\n",
      "{'__module__': '__main__', 'setXY': <function CC.setXY at 0x0000015504CCACA0>, 'printXY': <function CC.printXY at 0x0000015504CCAC00>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}\n",
      "{'__module__': '__main__', 'setXY': <function CC.setXY at 0x0000015504CCACA0>, 'printXY': <function CC.printXY at 0x0000015504CCAC00>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}\n"
     ]
    }
   ],
   "source": [
    "class CC:\n",
    "    def setXY(self, x, y):\n",
    "        self.x = x\n",
    "        self.y = y\n",
    "\n",
    "    def printXY(self):\n",
    "        print(self.x, self.y)\n",
    "\n",
    "\n",
    "dd = CC()\n",
    "print(dd.__dict__)\n",
    "# {}\n",
    "\n",
    "print(vars(dd))\n",
    "# {}\n",
    "\n",
    "print(CC.__dict__)\n",
    "\n",
    "dd.setXY(4, 5)\n",
    "print(dd.__dict__)\n",
    "print(vars(dd))\n",
    "\n",
    "print(vars(CC))\n",
    "\n",
    "print(CC.__dict__)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0a884e6d-7cc9-4cd2-9a84-f28500a97d08",
   "metadata": {},
   "source": [
    "## 一些相关的内置函数（BIF）\n",
    "- issubclass(class, classinfo) 方法用于判断参数 class 是否是类型参数 classinfo 的子类。\n",
    "- 一个类被认为是其自身的子类。\n",
    "- classinfo可以是类对象的元组，只要class是其中任何一个候选类的子类，则返回True。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "95a9754b-de3a-4a4f-86f7-be26214cb4b2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "class A:\n",
    "    pass\n",
    "\n",
    "\n",
    "class B(A):\n",
    "    pass\n",
    "\n",
    "\n",
    "print(issubclass(B, A))  # True\n",
    "print(issubclass(B, B))  # True\n",
    "print(issubclass(A, B))  # False\n",
    "print(issubclass(B, object))  # True"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "819858c9-4dd9-4408-a36e-527607f4d5f1",
   "metadata": {},
   "source": [
    "- isinstance(object, classinfo) 方法用于判断一个对象是否是一个已知的类型，类似type()。\n",
    "- type()不会认为子类是一种父类类型，不考虑继承关系。\n",
    "- isinstance()会认为子类是一种父类类型，考虑继承关系。\n",
    "- 如果第一个参数不是对象，则永远返回False。\n",
    "- 如果第二个参数不是类或者由类对象组成的元组，会抛出一个TypeError异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "1bb8972a-f749-4f05-ac3f-684adf2ec531",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "True\n",
      "True\n",
      "True\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "a = 2\n",
    "print(isinstance(a, int))  # True\n",
    "print(isinstance(a, str))  # False\n",
    "print(isinstance(a, (str, int, list)))  # True\n",
    "\n",
    "\n",
    "class A:\n",
    "    pass\n",
    "\n",
    "\n",
    "class B(A):\n",
    "    pass\n",
    "\n",
    "\n",
    "print(isinstance(A(), A))  # True\n",
    "print(type(A()) == A)  # True\n",
    "print(isinstance(B(), A))  # True\n",
    "print(type(B()) == A)  # False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba0e0c8b-4e8b-406a-9bac-5d440a3b40b0",
   "metadata": {},
   "source": [
    "- hasattr(object, name)用于判断对象是否包含对应的属性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "4d8c5104-5957-43ca-9ed0-324ec054fac5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "class Coordinate:\n",
    "    x = 10\n",
    "    y = -5\n",
    "    z = 0\n",
    "\n",
    "\n",
    "point1 = Coordinate()\n",
    "print(hasattr(point1, 'x'))  # True\n",
    "print(hasattr(point1, 'y'))  # True\n",
    "print(hasattr(point1, 'z'))  # True\n",
    "print(hasattr(point1, 'no'))  # False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "329e4aa5-f414-4054-9a15-9ed3b86389d5",
   "metadata": {},
   "source": [
    "- getattr(object, name[, default])用于返回一个对象属性值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "e00f6c09-9f47-499f-8ed3-696e6c5d52f4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "3\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'A' object has no attribute 'bar2'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[24], line 8\u001b[0m\n\u001b[0;32m      6\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mgetattr\u001b[39m(a, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mbar\u001b[39m\u001b[38;5;124m'\u001b[39m))  \u001b[38;5;66;03m# 1\u001b[39;00m\n\u001b[0;32m      7\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mgetattr\u001b[39m(a, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mbar2\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;241m3\u001b[39m))  \u001b[38;5;66;03m# 3\u001b[39;00m\n\u001b[1;32m----> 8\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28;43mgetattr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43ma\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mbar2\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m)\n\u001b[0;32m      9\u001b[0m \u001b[38;5;66;03m# AttributeError: 'A' object has no attribute 'bar2'\u001b[39;00m\n",
      "\u001b[1;31mAttributeError\u001b[0m: 'A' object has no attribute 'bar2'"
     ]
    }
   ],
   "source": [
    "class A(object):\n",
    "    bar = 1\n",
    "\n",
    "\n",
    "a = A()\n",
    "print(getattr(a, 'bar'))  # 1\n",
    "print(getattr(a, 'bar2', 3))  # 3\n",
    "print(getattr(a, 'bar2'))\n",
    "# AttributeError: 'A' object has no attribute 'bar2'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "0a58ea73-9537-4bb7-a8d2-d05cf6a2c531",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 1\n"
     ]
    }
   ],
   "source": [
    "class A(object):\n",
    "    def set(self, a, b):\n",
    "        x = a\n",
    "        a = b\n",
    "        b = x\n",
    "        print(a, b)\n",
    "\n",
    "\n",
    "a = A()\n",
    "c = getattr(a, 'set')\n",
    "c(a='1', b='2')  # 2 1\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed4162ac-5905-4fc5-8df0-576e871ed1ee",
   "metadata": {},
   "source": [
    "- setattr(object, name, value)对应函数 getattr()，用于设置属性值，该属性不一定是存在的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "93b614c8-d1ea-4349-8732-edea8fc8c857",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "5\n",
      "28\n"
     ]
    }
   ],
   "source": [
    "class A(object):\n",
    "    bar = 1\n",
    "\n",
    "\n",
    "a = A()\n",
    "print(getattr(a, 'bar'))  # 1\n",
    "setattr(a, 'bar', 5)\n",
    "print(a.bar)  # 5\n",
    "setattr(a, \"age\", 28)\n",
    "print(a.age)  # 28"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e842f25-c1d7-4ada-9fb6-6e755229ddbc",
   "metadata": {},
   "source": [
    "- delattr(object, name)用于删除属性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "50257bfd-0882-4de8-9445-60b3b892a272",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x =  10\n",
      "y =  -5\n",
      "z =  0\n",
      "--删除 z 属性后--\n",
      "x =  10\n",
      "y =  -5\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'Coordinate' object has no attribute 'z'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[27], line 20\u001b[0m\n\u001b[0;32m     17\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124my = \u001b[39m\u001b[38;5;124m'\u001b[39m, point1\u001b[38;5;241m.\u001b[39my)  \u001b[38;5;66;03m# y =  -5\u001b[39;00m\n\u001b[0;32m     19\u001b[0m \u001b[38;5;66;03m# 触发错误\u001b[39;00m\n\u001b[1;32m---> 20\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mz = \u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[43mpoint1\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mz\u001b[49m)\n\u001b[0;32m     21\u001b[0m \u001b[38;5;66;03m# AttributeError: 'Coordinate' object has no attribute 'z'\u001b[39;00m\n",
      "\u001b[1;31mAttributeError\u001b[0m: 'Coordinate' object has no attribute 'z'"
     ]
    }
   ],
   "source": [
    "class Coordinate:\n",
    "    x = 10\n",
    "    y = -5\n",
    "    z = 0\n",
    "\n",
    "\n",
    "point1 = Coordinate()\n",
    "\n",
    "print('x = ', point1.x)  # x =  10\n",
    "print('y = ', point1.y)  # y =  -5\n",
    "print('z = ', point1.z)  # z =  0\n",
    "\n",
    "delattr(Coordinate, 'z')\n",
    "\n",
    "print('--删除 z 属性后--')  # --删除 z 属性后--\n",
    "print('x = ', point1.x)  # x =  10\n",
    "print('y = ', point1.y)  # y =  -5\n",
    "\n",
    "# 触发错误\n",
    "print('z = ', point1.z)\n",
    "# AttributeError: 'Coordinate' object has no attribute 'z'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6540d1b-bba9-4ee0-8d16-000298d7687d",
   "metadata": {},
   "source": [
    "- class property([fget[, fset[, fdel[, doc]]]])用于在新式类中返回属性值。\n",
    "  - fget -- 获取属性值的函数\n",
    "  - fset -- 设置属性值的函数\n",
    "  - fdel -- 删除属性值函数\n",
    "  - doc -- 属性描述信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "2aa0fbd9-c3dd-4f07-ab5e-bf95c4233565",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<property object at 0x0000015504D3AC00>\n",
      "2\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'C' object has no attribute '_C__x'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[30], line 24\u001b[0m\n\u001b[0;32m     21\u001b[0m \u001b[38;5;28mprint\u001b[39m(cc\u001b[38;5;241m.\u001b[39mx)  \u001b[38;5;66;03m# 2\u001b[39;00m\n\u001b[0;32m     23\u001b[0m \u001b[38;5;28;01mdel\u001b[39;00m cc\u001b[38;5;241m.\u001b[39mx\n\u001b[1;32m---> 24\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43mcc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mx\u001b[49m)\n\u001b[0;32m     25\u001b[0m \u001b[38;5;66;03m# AttributeError: 'C' object has no attribute '_C__x'\u001b[39;00m\n",
      "Cell \u001b[1;32mIn[30], line 6\u001b[0m, in \u001b[0;36mC.getx\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mgetx\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n\u001b[1;32m----> 6\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__x\u001b[49m\n",
      "\u001b[1;31mAttributeError\u001b[0m: 'C' object has no attribute '_C__x'"
     ]
    }
   ],
   "source": [
    "class C(object):\n",
    "    def __init__(self):\n",
    "        self.__x = None\n",
    "\n",
    "    def getx(self):\n",
    "        return self.__x\n",
    "\n",
    "    def setx(self, value):\n",
    "        self.__x = value\n",
    "\n",
    "    def delx(self):\n",
    "        del self.__x\n",
    "\n",
    "    x = property(getx, setx, delx, \"I'm the 'x' property.\")\n",
    "\n",
    "print(C.x)\n",
    "\n",
    "cc = C()\n",
    "\n",
    "cc.x = 2\n",
    "print(cc.x)  # 2\n",
    "\n",
    "del cc.x\n",
    "print(cc.x)\n",
    "# AttributeError: 'C' object has no attribute '_C__x'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6f4ef369-a034-4d98-9f16-d836bdbf8fea",
   "metadata": {},
   "source": [
    "## 魔法方法\n",
    "魔法方法总是被双下划线包围，例如__init__。\n",
    "\n",
    "魔法方法是面向对象的 Python 的一切，如果你不知道魔法方法，说明你还没能意识到面向对象的 Python 的强大。\n",
    "\n",
    "魔法方法的“魔力”体现在它们总能够在适当的时候被自动调用。\n",
    "\n",
    "魔法方法的第一个参数应为cls（类方法） 或者self（实例方法）。\n",
    "\n",
    "- cls：代表一个类的名称\n",
    "- self：代表一个实例对象的名称\n",
    "### 基本的魔法方法\n",
    "- `__init__`(self\\[, ...]) 构造器，当一个实例被创建的时候调用的初始化方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "28487a99-b50c-41aa-8e05-130853b2ea15",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "18\n",
      "20\n"
     ]
    }
   ],
   "source": [
    "class Rectangle:\n",
    "    def __init__(self, x, y):\n",
    "        self.x = x\n",
    "        self.y = y\n",
    "\n",
    "    def getPeri(self):\n",
    "        return (self.x + self.y) * 2\n",
    "\n",
    "    def getArea(self):\n",
    "        return self.x * self.y\n",
    "\n",
    "\n",
    "rect = Rectangle(4, 5)\n",
    "print(rect.getPeri())  # 18\n",
    "print(rect.getArea())  # 20"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6c7677c-df31-481b-bdb3-e9dc92b04993",
   "metadata": {},
   "source": [
    "- `__new__`(cls[, ...]) 在一个对象实例化的时候所调用的第一个方法，在调用`__init__`初始化前，先调用`__new__`。\n",
    "  - `__new__`至少要有一个参数cls，代表要实例化的类，此参数在实例化时由 Python 解释器自动提供，后面的参数直接传递给`__init_`_。\n",
    "  - `__new__`对当前类进行了实例化，并将实例返回，传给`__init__`的self。但是，执行了`__new__`，并不一定会进入`__init__`，只有`__new__`返回了，当前类cls的实例，当前类的`__init__`才会进入。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "2cc6cecc-2f44-408f-93ec-6d4ae57a4996",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "into B __new__\n",
      "<class '__main__.B'>\n",
      "into A __new__\n",
      "<class '__main__.B'>\n",
      "into B __init__\n"
     ]
    }
   ],
   "source": [
    "class A(object):\n",
    "    def __init__(self, value):\n",
    "        print(\"into A __init__\")\n",
    "        self.value = value\n",
    "\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        print(\"into A __new__\")\n",
    "        print(cls)\n",
    "        return object.__new__(cls)\n",
    "\n",
    "\n",
    "class B(A):\n",
    "    def __init__(self, value):\n",
    "        print(\"into B __init__\")\n",
    "        self.value = value\n",
    "\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        print(\"into B __new__\")\n",
    "        print(cls)\n",
    "        return super().__new__(cls, *args, **kwargs)\n",
    "\n",
    "\n",
    "b = B(10)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "911e4b35-6f40-4a2d-87c3-10004027c8ac",
   "metadata": {},
   "source": [
    "- 若__new__没有正确返回当前类cls的实例，那__init__是不会被调用的，即使是父类的实例也不行，将没有__init__被调用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "21956cb3-1379-4435-b1d2-6a77d5d9ebec",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "into B __new__\n",
      "<class '__main__.B'>\n",
      "into A __new__\n",
      "<class '__main__.A'>\n"
     ]
    }
   ],
   "source": [
    "\n",
    "class A(object):\n",
    "    def __init__(self, value):\n",
    "        print(\"into A __init__\")\n",
    "        self.value = value\n",
    "\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        print(\"into A __new__\")\n",
    "        print(cls)\n",
    "        return object.__new__(cls)\n",
    "\n",
    "\n",
    "class B(A):\n",
    "    def __init__(self, value):\n",
    "        print(\"into B __init__\")\n",
    "        self.value = value\n",
    "\n",
    "    def __new__(cls, *args, **kwargs):\n",
    "        print(\"into B __new__\")\n",
    "        print(cls)\n",
    "        return super().__new__(A, *args, **kwargs)  # 改动了cls变为A\n",
    "\n",
    "b = B(10)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "56c8773d-e863-4302-9231-335e4a9a558d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1464658925408\n",
      "1464658922768\n",
      "1464658929296\n",
      "1464658929296\n"
     ]
    }
   ],
   "source": [
    "# 利用__new__实现单例模式。\n",
    "class Earth:\n",
    "    pass\n",
    "\n",
    "a = Earth()\n",
    "print(id(a))  # 260728291456\n",
    "b = Earth()\n",
    "print(id(b))  # 260728291624\n",
    "\n",
    "class Earth:\n",
    "    __instance = None  # 定义一个类属性做判断\n",
    "\n",
    "    def __new__(cls):\n",
    "        if cls.__instance is None:\n",
    "            cls.__instance = object.__new__(cls)\n",
    "            return cls.__instance\n",
    "        else:\n",
    "            return cls.__instance\n",
    "\n",
    "\n",
    "a = Earth()\n",
    "print(id(a))  # 512320401648\n",
    "b = Earth()\n",
    "print(id(b))  # 512320401648"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa11869c-a0fa-497e-b82d-b3d169b83046",
   "metadata": {},
   "source": [
    "- __new__方法主要是当你继承一些不可变的 class 时（比如int, str, tuple）， 提供给你一个自定义这些类的实例化过程的途径。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "0aa07fa2-2a8e-4616-92ab-0d083292f4bb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I LOVE LSGOGROUP\n"
     ]
    }
   ],
   "source": [
    "class CapStr(str):\n",
    "    def __new__(cls, string):\n",
    "        string = string.upper()\n",
    "        return str.__new__(cls, string)\n",
    "\n",
    "\n",
    "a = CapStr(\"i love lsgogroup\")\n",
    "print(a)  # I LOVE LSGOGROUP"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "625bdb10-263e-4ae0-bb6f-ff178ad03658",
   "metadata": {},
   "source": [
    "- __del__(self) 析构器，当一个对象将要被系统回收之时调用的方法。\n",
    ">Python 采用自动引用计数（ARC）方式来回收对象所占用的空间，当程序中有一个变量引用该 Python 对象时，Python 会自动保证该对象引用计数为 1；当程序中有两个变量引用该 Python 对象时，Python 会自动保证该对象引用计数为 2，依此类推，如果一个对象的引用计数变成了 0，则说明程序中不再有变量引用该对象，表明程序不再需要该对象，因此 Python 就会回收该对象。\n",
    "大部分时候，Python 的 ARC 都能准确、高效地回收系统中的每个对象。但如果系统中出现循环引用的情况，比如对象 a 持有一个实例变量引用对象 b，而对象 b 又持有一个实例变量引用对象 a，此时两个对象的引用计数都是 1，而实际上程序已经不再有变量引用它们，系统应该回收它们，此时 Python 的垃圾回收器就可能没那么快，要等专门的循环垃圾回收器（Cyclic Garbage Collector）来检测并回收这种引用循环。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "52de7c6e-b1f6-4b07-9788-f0486bb31c97",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "into C __init__\n",
      "into C __del__\n"
     ]
    }
   ],
   "source": [
    "class C(object):\n",
    "    def __init__(self):\n",
    "        print('into C __init__')\n",
    "\n",
    "    def __del__(self):\n",
    "        print('into C __del__')\n",
    "\n",
    "\n",
    "c1 = C()\n",
    "# into C __init__\n",
    "c2 = c1\n",
    "c3 = c2\n",
    "del c3\n",
    "del c2\n",
    "del c1\n",
    "# into C __del__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "170fc1b3-cbcb-45aa-9ed9-a24f5d3e5c6b",
   "metadata": {},
   "source": [
    "- `__str__(self)`:\n",
    "\n",
    "  - 当你打印一个对象的时候，触发__str__\n",
    "  - 当你使用%s格式化的时候，触发__str__\n",
    "  - str强转数据类型的时候，触发__str__\n",
    "- `__repr__(self)`：\n",
    "\n",
    "  - repr是str的备胎\n",
    "  - 有__str__的时候执行__str__,没有实现__str__的时候，执行__repr__\n",
    "  - repr(obj)内置函数对应的结果是__repr__的返回值\n",
    "  - 当你使用%r格式化的时候 触发__repr__"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "b9ff01dd-6520-45cf-ae65-52c9da36e94e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "名字是:汤姆 , 年龄是:30\n",
      "名字是:汤姆 , 年龄是:30\n",
      "Cat:(汤姆,30)\n",
      "汤姆在吃鱼....\n",
      "名字是:汤姆, 年龄是:30\n",
      "Cat:(汤姆,30)\n",
      "名字是:汤姆 , 年龄是:30\n"
     ]
    }
   ],
   "source": [
    "class Cat:\n",
    "    \"\"\"定义一个猫类\"\"\"\n",
    "\n",
    "    def __init__(self, new_name, new_age):\n",
    "        \"\"\"在创建完对象之后 会自动调用, 它完成对象的初始化的功能\"\"\"\n",
    "        self.name = new_name\n",
    "        self.age = new_age\n",
    "\n",
    "    def __str__(self):\n",
    "        \"\"\"返回一个对象的描述信息\"\"\"\n",
    "        return \"名字是:%s , 年龄是:%d\" % (self.name, self.age)\n",
    "        \n",
    "    def __repr__(self):\n",
    "        \"\"\"返回一个对象的描述信息\"\"\"\n",
    "        return \"Cat:(%s,%d)\" % (self.name, self.age)\n",
    "\n",
    "    def eat(self):\n",
    "        print(\"%s在吃鱼....\" % self.name)\n",
    "\n",
    "    def drink(self):\n",
    "        print(\"%s在喝可乐...\" % self.name)\n",
    "\n",
    "    def introduce(self):\n",
    "        print(\"名字是:%s, 年龄是:%d\" % (self.name, self.age))\n",
    "\n",
    "\n",
    "# 创建了一个对象\n",
    "tom = Cat(\"汤姆\", 30)\n",
    "print(tom)  # 名字是:汤姆 , 年龄是:30\n",
    "print(str(tom)) # 名字是:汤姆 , 年龄是:30\n",
    "print(repr(tom))  # Cat:(汤姆,30)\n",
    "tom.eat()  # 汤姆在吃鱼....\n",
    "tom.introduce()  # 名字是:汤姆, 年龄是:30\n",
    "print('%r' % tom)  # Cat:(汤姆,30)\n",
    "print('%s' % tom)  # 名字是:汤姆 , 年龄是:30"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e5d9a6e-aa81-433c-82e3-6d3ca4aac6b3",
   "metadata": {},
   "source": [
    "`__str__`(self) 的返回结果可读性强。也就是说，`__str__` 的意义是得到便于人们阅读的信息，就像下面的 '2019-10-11' 一样。\n",
    "\n",
    "`__repr__`(self) 的返回结果应更准确。怎么说，`__repr__` 存在的目的在于调试，便于开发者使用。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "d1f46afb-7f96-4319-9b7f-eb36e3b8fbdc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2025-08-25\n",
      "datetime.date(2025, 8, 25)\n",
      "2025-08-25\n",
      "datetime.date(2025, 8, 25)\n"
     ]
    }
   ],
   "source": [
    "import datetime\n",
    "\n",
    "today = datetime.date.today()\n",
    "print(str(today))  # 2019-10-11\n",
    "print(repr(today))  # datetime.date(2019, 10, 11)\n",
    "print('%s' %today)  # 2019-10-11\n",
    "print('%r' %today)  # datetime.date(2019, 10, 11)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df6e8daf-9fd6-4d07-a5fa-193a773e27b7",
   "metadata": {},
   "source": [
    "## 算术运算符\n",
    "类型工厂函数，指的是“不通过类而是通过函数来创建对象”。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "2e691ef6-e268-4ee8-a03d-b597daf8f332",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'builtin_function_or_method'>\n",
      "<class 'builtin_function_or_method'>\n",
      "<class 'type'>\n",
      "<class 'type'>\n",
      "<class 'type'>\n",
      "<class 'type'>\n",
      "123\n",
      "[1, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "class C:\n",
    "    pass\n",
    "\n",
    "\n",
    "print(type(len))  # <class 'builtin_function_or_method'>\n",
    "print(type(dir))  # <class 'builtin_function_or_method'>\n",
    "print(type(int))  # <class 'type'>\n",
    "print(type(list))  # <class 'type'>\n",
    "print(type(tuple))  # <class 'type'>\n",
    "print(type(C))  # <class 'type'>\n",
    "print(int('123'))  # 123\n",
    "\n",
    "# 这个例子中list工厂函数把一个元祖对象加工成了一个列表对象。\n",
    "print(list((1, 2, 3)))  # [1, 2, 3]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8bb69638-a5d0-456f-b077-5785847ad431",
   "metadata": {},
   "source": [
    "- `__add__`(self, other)定义加法的行为：+\n",
    "- `__sub__`(self, other)定义减法的行为：-"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "d689aef2-df59-4102-86ee-9cf36d653020",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "高为 10  重为 5\n",
      "高为 20  重为 10\n",
      "高为 10  重为 5\n",
      "高为 30  重为 15\n"
     ]
    }
   ],
   "source": [
    "class MyClass:\n",
    "\n",
    "    def __init__(self, height, weight):\n",
    "        self.height = height\n",
    "        self.weight = weight\n",
    "\n",
    "    # 两个对象的长相加，宽相加.返回一个新的类\n",
    "    def __add__(self, others):\n",
    "        return MyClass(self.height + others.height, self.weight + others.weight)\n",
    "\n",
    "    # 两个对象的宽相减，长相减.返回一个新的类\n",
    "    def __sub__(self, others):\n",
    "        return MyClass(self.height - others.height, self.weight - others.weight)\n",
    "\n",
    "    # 说一下自己的参数\n",
    "    def intro(self):\n",
    "        print(\"高为\", self.height, \" 重为\", self.weight)\n",
    "\n",
    "\n",
    "def main():\n",
    "    a = MyClass(height=10, weight=5)\n",
    "    a.intro()\n",
    "\n",
    "    b = MyClass(height=20, weight=10)\n",
    "    b.intro()\n",
    "\n",
    "    c = b - a\n",
    "    c.intro()\n",
    "\n",
    "    d = a + b\n",
    "    d.intro()\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()\n",
    "\n",
    "# 高为 10  重为 5\n",
    "# 高为 20  重为 10\n",
    "# 高为 10  重为 5\n",
    "# 高为 30  重为 15"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eb290679-87c4-409e-86a3-ffff47d1e3aa",
   "metadata": {},
   "source": [
    "- `__mul__`(self, other)定义乘法的行为：*\n",
    "- `__truediv__`(self, other)定义真除法的行为：/\n",
    "- `__floordiv__`(self, other)定义整数除法的行为：//\n",
    "- `__mod__`(self, other) 定义取模算法的行为：%\n",
    "- `__divmod__`(self, other)定义当被 divmod() 调用时的行为\n",
    "- divmod(a, b)把除数和余数运算结果结合起来，返回一个包含商和余数的元组(a // b, a % b)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "d785fbf2-f634-4304-9aeb-1277356bc12a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(3, 1)\n",
      "(4, 0)\n"
     ]
    }
   ],
   "source": [
    "print(divmod(7, 2))  # (3, 1)\n",
    "print(divmod(8, 2))  # (4, 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3615cfd-346b-48e9-9612-4bcde8a4eec8",
   "metadata": {},
   "source": [
    "- `__pow__`(self, other\\[, module\\])定义当被 power() 调用或 ** 运算时的行为\n",
    "- `__lshift__`(self, other)定义按位左移位的行为：<<\n",
    "- `__rshift__`(self, other)定义按位右移位的行为：>>\n",
    "- `__and__`(self, other)定义按位与操作的行为：&\n",
    "- `__xor__`(self, other)定义按位异或操作的行为：^\n",
    "- `__or__`(self, other)定义按位或操作的行为：|"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54c737d1-bb44-4ec0-bb3c-0ce196dc81b6",
   "metadata": {},
   "source": [
    "### 反算术运算符\n",
    "反运算魔方方法，与算术运算符保持一一对应，不同之处就是反运算的魔法方法多了一个“r”。当文件左操作不支持相应的操作时被调用。\n",
    "\n",
    "- `__radd__`(self, other)定义加法的行为：+\n",
    "- `__rsub__`(self, other)定义减法的行为：-\n",
    "- `__rmul__`(self, other)定义乘法的行为：*\n",
    "- `__rtruediv__`(self, other)定义真除法的行为：/\n",
    "- `__rfloordiv__`(self, other)定义整数除法的行为：//\n",
    "- `__rmod__`(self, other) 定义取模算法的行为：%\n",
    "- `__rdivmod__`(self, other)定义当被 divmod() 调用时的行为\n",
    "- `__rpow__`(self, other\\[, module])定义当被 power() 调用或 ** 运算时的行为\n",
    "- `__rlshift__`(self, other)定义按位左移位的行为：<<\n",
    "- `__rrshift__`(self, other)定义按位右移位的行为：>>\n",
    "- `__rand__`(self, other)定义按位与操作的行为：&\n",
    "- `__rxor__`(self, other)定义按位异或操作的行为：^\n",
    "- `__ror__`(self, other)定义按位或操作的行为：|\n",
    "\n",
    "`a + b`\n",
    "\n",
    "这里加数是a，被加数是b，因此是a主动，反运算就是如果a对象的__add__()方法没有实现或者不支持相应的操作，那么 Python 就会调用b的__radd__()方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "d6683fcd-49c9-4d96-8af4-d8e8533fc376",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8\n",
      "-2\n"
     ]
    }
   ],
   "source": [
    "class Nint(int):\n",
    "    def __radd__(self, other):\n",
    "        return int.__sub__(other, self) # 注意 self 在后面\n",
    "\n",
    "\n",
    "a = Nint(5)\n",
    "b = Nint(3)\n",
    "print(a + b)  # 8\n",
    "print(1 + b)  # -2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0494b6b8-9117-4684-ad20-27abf06b07fb",
   "metadata": {},
   "source": [
    "### 增量赋值运算符\n",
    "- `__iadd__`(self, other)定义赋值加法的行为：+=\n",
    "- `__isub__`(self, other)定义赋值减法的行为：-=\n",
    "- `__imul__`(self, other)定义赋值乘法的行为：*=\n",
    "- `__itruediv__`(self, other)定义赋值真除法的行为：/=\n",
    "- `__ifloordiv__`(self, other)定义赋值整数除法的行为：//=\n",
    "- `__imod__`(self, other)定义赋值取模算法的行为：%=\n",
    "- `__ipow__`(self, other\\[, modulo])定义赋值幂运算的行为：**=\n",
    "- `__ilshift__`(self, other)定义赋值按位左移位的行为：<<=\n",
    "- `__irshift__`(self, other)定义赋值按位右移位的行为：>>=\n",
    "- `__iand__`(self, other)定义赋值按位与操作的行为：&=\n",
    "- `__ixor__`(self, other)定义赋值按位异或操作的行为：^=\n",
    "- `__ior__`(self, other)定义赋值按位或操作的行为：|=\n",
    "\n",
    "### 一元运算符\n",
    "- `__neg__`(self)定义正号的行为：+x\n",
    "- `__pos__`(self)定义负号的行为：-x\n",
    "- `__abs__`(self)定义当被abs()调用时的行为\n",
    "- `__invert__`(self)定义按位求反的行为：~x\n",
    "\n",
    "### 属性访问\n",
    "- `__getattr__`(self, name): 定义当用户试图获取一个不存在的属性时的行为。\n",
    "- `__getattribute__`(self, name)：定义当该类的属性被访问时的行为（先调用该方法，查看是否存在该属性，若不存在，接着去调用__getattr__）。\n",
    "- `__setattr__`(self, name, value)：定义当一个属性被设置时的行为。\n",
    "- `__delattr__`(self, name)：定义当一个属性被删除时的行为。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "a2502726-cf75-4ee4-8097-54e4ab16c1bb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__getattribute__\n",
      "__getattr__\n",
      "__setattr__\n",
      "__delattr__\n"
     ]
    }
   ],
   "source": [
    "class C:\n",
    "    def __getattribute__(self, item):\n",
    "        print('__getattribute__')\n",
    "        return super().__getattribute__(item)\n",
    "\n",
    "    def __getattr__(self, item):\n",
    "        print('__getattr__')\n",
    "\n",
    "    def __setattr__(self, key, value):\n",
    "        print('__setattr__')\n",
    "        super().__setattr__(key, value)\n",
    "\n",
    "    def __delattr__(self, item):\n",
    "        print('__delattr__')\n",
    "        super().__delattr__(item)\n",
    "\n",
    "\n",
    "c = C()\n",
    "c.x\n",
    "# __getattribute__\n",
    "# __getattr__\n",
    "\n",
    "c.x = 1\n",
    "# __setattr__\n",
    "\n",
    "del c.x\n",
    "# __delattr__"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "042ea786-8030-4b81-b7c8-f169f2572ef4",
   "metadata": {},
   "source": [
    "### 描述符\n",
    "描述符就是将某种特殊类型的类的实例指派给另一个类的属性。\n",
    "\n",
    "- `__get__`(self, instance, owner)用于访问属性，它返回属性的值。\n",
    "- `__set__`(self, instance, value)将在属性分配操作中调用，不返回任何内容。\n",
    "- `__del__`(self, instance)控制删除操作，不返回任何内容。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "5babaebe-a9ff-4591-8295-314d57330cc4",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "__get__ <__main__.MyDecriptor object at 0x0000015504679A60> <__main__.Test object at 0x00000155047A4770> <class '__main__.Test'>\n",
      "__set__ <__main__.MyDecriptor object at 0x0000015504679A60> <__main__.Test object at 0x00000155047A4770> x-man\n",
      "__delete__ <__main__.MyDecriptor object at 0x0000015504679A60> <__main__.Test object at 0x00000155047A4770>\n"
     ]
    }
   ],
   "source": [
    "class MyDecriptor:\n",
    "    def __get__(self, instance, owner):\n",
    "        print('__get__', self, instance, owner)\n",
    "\n",
    "    def __set__(self, instance, value):\n",
    "        print('__set__', self, instance, value)\n",
    "\n",
    "    def __delete__(self, instance):\n",
    "        print('__delete__', self, instance)\n",
    "\n",
    "\n",
    "class Test:\n",
    "    x = MyDecriptor()\n",
    "\n",
    "\n",
    "t = Test()\n",
    "t.x\n",
    "# __get__ <__main__.MyDecriptor object at 0x000000CEAAEB6B00> <__main__.Test object at 0x000000CEABDC0898> <class '__main__.Test'>\n",
    "\n",
    "t.x = 'x-man'\n",
    "# __set__ <__main__.MyDecriptor object at 0x00000023687C6B00> <__main__.Test object at 0x00000023696B0940> x-man\n",
    "\n",
    "del t.x\n",
    "# __delete__ <__main__.MyDecriptor object at 0x000000EC9B160A90> <__main__.Test object at 0x000000EC9B160B38>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf87d381-0799-404b-aac7-5920710d561a",
   "metadata": {},
   "source": [
    "### 定制序列\n",
    "协议（Protocols）与其它编程语言中的接口很相似，它规定你哪些方法必须要定义。然而，在 Python 中的协议就显得不那么正式。事实上，在 Python 中，协议更像是一种指南。\n",
    "\n",
    "容器类型的协议\n",
    "\n",
    "- 如果说你希望定制的容器是不可变的话，你只需要定义`__len__()`和`__getitem__()`方法。\n",
    "- 如果你希望定制的容器是可变的话，除了`__len__()`和`__getitem__()`方法，你还需要定义`__setitem__()`和`__delitem__()`两个方法。\n",
    "- `__len__(self)`定义当被len()调用时的行为（返回容器中元素的个数）。\n",
    "- `__getitem__(self, key)`定义获取容器中元素的行为，相当于self\\[key]。\n",
    "- `__setitem__(self, key, value)`定义设置容器中指定元素的行为，相当于self\\[key] = value。\n",
    "- `__delitem__(self, key)`定义删除容器中指定元素的行为，相当于del self\\[key]。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "ad5e8477-0aad-48de-a2d9-e79236f5e026",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "6\n",
      "7\n",
      "{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}\n",
      "{0: 0, 1: 1, 2: 1, 3: 0, 4: 0}\n"
     ]
    }
   ],
   "source": [
    "class CountList:\n",
    "    def __init__(self, *args):\n",
    "        self.values = [x for x in args]\n",
    "        self.count = {}.fromkeys(range(len(self.values)), 0)\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.values)\n",
    "\n",
    "    def __getitem__(self, item):\n",
    "        self.count[item] += 1\n",
    "        return self.values[item]\n",
    "\n",
    "\n",
    "c1 = CountList(1, 3, 5, 7, 9)\n",
    "c2 = CountList(2, 4, 6, 8, 10)\n",
    "print(c1[1])  # 3\n",
    "print(c2[2])  # 6\n",
    "print(c1[1] + c2[1])  # 7\n",
    "\n",
    "print(c1.count)\n",
    "# {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}\n",
    "\n",
    "print(c2.count)\n",
    "# {0: 0, 1: 1, 2: 1, 3: 0, 4: 0}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "4a566c7c-0863-451b-89c4-a1dbbf79fda1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'list'>\n",
      "<class 'dict'>\n",
      "3\n",
      "6\n",
      "15\n",
      "{0: 0, 1: 2, 2: 0, 3: 0, 4: 0}\n",
      "{0: 0, 1: 0, 2: 2, 3: 0, 4: 0}\n",
      "{0: 0, 1: 0, 2: 0, 3: 0}\n"
     ]
    }
   ],
   "source": [
    "class CountList:\n",
    "    def __init__(self, *args):\n",
    "        self.values = [x for x in args]\n",
    "        self.count = {}.fromkeys(range(len(self.values)), 0)\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.values)\n",
    "\n",
    "    def __getitem__(self, item):\n",
    "        self.count[item] += 1\n",
    "        return self.values[item]\n",
    "\n",
    "    def __setitem__(self, key, value):\n",
    "        self.values[key] = value\n",
    "\n",
    "    def __delitem__(self, key):\n",
    "        del self.values[key]\n",
    "        for i in range(0, len(self.values)):\n",
    "            if i >= key:\n",
    "                self.count[i] = self.count[i + 1]\n",
    "        self.count.pop(len(self.values))\n",
    "\n",
    "\n",
    "c1 = CountList(1, 3, 5, 7, 9)\n",
    "c2 = CountList(2, 4, 6, 8, 10)\n",
    "print(type(c1.values))\n",
    "print(type(c1.count))\n",
    "print(c1[1])  # 3\n",
    "print(c2[2])  # 6\n",
    "c2[2] = 12\n",
    "print(c1[1] + c2[2])  # 15\n",
    "print(c1.count)\n",
    "# {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}\n",
    "print(c2.count)\n",
    "# {0: 0, 1: 0, 2: 2, 3: 0, 4: 0}\n",
    "del c1[1]\n",
    "print(c1.count)\n",
    "# {0: 0, 1: 0, 2: 0, 3: 0}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cbaaeb6b-d071-4b03-b333-937440934d84",
   "metadata": {},
   "source": [
    "### 迭代器\n",
    "- 迭代是 Python 最强大的功能之一，是访问集合元素的一种方式。\n",
    "- 迭代器是一个可以记住遍历的位置的对象。\n",
    "- 迭代器对象从集合的第一个元素开始访问，直到所有的元素被访问完结束。\n",
    "- 迭代器只能往前不会后退。\n",
    "- 字符串，列表或元组对象都可用于创建迭代器："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "1da3e249-d989-47d5-b2ee-5ee292f9a1f1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "l\n",
      "s\n",
      "g\n",
      "o\n",
      "g\n",
      "r\n",
      "o\n",
      "u\n",
      "p\n",
      "\n",
      "-----------------------------------------------------------------\n",
      "\n",
      "l\n",
      "s\n",
      "g\n",
      "o\n",
      "g\n",
      "r\n",
      "o\n",
      "u\n",
      "p\n"
     ]
    }
   ],
   "source": [
    "string = 'lsgogroup'\n",
    "for c in string:\n",
    "    print(c)\n",
    "print(\"\\n-----------------------------------------------------------------\\n\")\n",
    "for c in iter(string):\n",
    "    print(c)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "a2f74b54-13f3-4db7-92ef-54b3cc29748f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "B -> 百度\n",
      "A -> 阿里\n",
      "T -> 腾讯\n",
      "\n",
      "-----------------------------------------------------------------\n",
      "\n",
      "B -> 百度\n",
      "A -> 阿里\n",
      "T -> 腾讯\n"
     ]
    }
   ],
   "source": [
    "links = {'B': '百度', 'A': '阿里', 'T': '腾讯'}\n",
    "for each in links:\n",
    "    print('%s -> %s' % (each, links[each]))\n",
    "    \n",
    "print(\"\\n-----------------------------------------------------------------\\n\")\n",
    "\n",
    "for each in iter(links):\n",
    "    print('%s -> %s' % (each, links[each]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ae33d27-6cfa-4ff5-8481-16e5c932aa80",
   "metadata": {},
   "source": [
    "- 迭代器有两个基本的方法：iter() 和 next()。\n",
    "- iter(object) 函数用来生成迭代器。\n",
    "- next(iterator\\[, default]) 返回迭代器的下一个项目。\n",
    "- iterator -- 可迭代对象\n",
    "- default -- 可选，用于设置在没有下一个元素时返回该默认值，如果不设置，又没有下一个元素则会触发 StopIteration 异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "8c86e8f1-71de-48ca-8ba7-f540e788a890",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "B\n",
      "A\n",
      "T\n",
      "B\n",
      "A\n",
      "T\n"
     ]
    },
    {
     "ename": "StopIteration",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[69], line 19\u001b[0m\n\u001b[0;32m     17\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mnext\u001b[39m(it))  \u001b[38;5;66;03m# A\u001b[39;00m\n\u001b[0;32m     18\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mnext\u001b[39m(it))  \u001b[38;5;66;03m# T\u001b[39;00m\n\u001b[1;32m---> 19\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28;43mnext\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mit\u001b[49m\u001b[43m)\u001b[49m)  \u001b[38;5;66;03m# StopIteration\u001b[39;00m\n",
      "\u001b[1;31mStopIteration\u001b[0m: "
     ]
    }
   ],
   "source": [
    "links = {'B': '百度', 'A': '阿里', 'T': '腾讯'}\n",
    "\n",
    "it = iter(links)\n",
    "while True:\n",
    "    try:\n",
    "        each = next(it)\n",
    "    except StopIteration:\n",
    "        break\n",
    "    print(each)\n",
    "\n",
    "# B\n",
    "# A\n",
    "# T\n",
    "\n",
    "it = iter(links)\n",
    "print(next(it))  # B\n",
    "print(next(it))  # A\n",
    "print(next(it))  # T\n",
    "print(next(it))  # StopIteration"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6983243-8e16-4c61-8f57-c150d9926cae",
   "metadata": {},
   "source": [
    "把一个类作为一个迭代器使用需要在类中实现两个魔法方法 `__iter__()` 与 `__next__()` 。\n",
    "\n",
    "- `__iter__(self)`定义当迭代容器中的元素的行为，返回一个特殊的迭代器对象， 这个迭代器对象实现了 `__next__()` 方法并通过 StopIteration 异常标识迭代的完成。\n",
    "- `__next__()` 返回下一个迭代器对象。\n",
    "- StopIteration 异常用于标识迭代的完成，防止出现无限循环的情况，在 `__next__()` 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "id": "c9a50fb1-be6c-47f5-8b03-5fe877072b0f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 1 2 3 5 8 13 21 34 55 89 "
     ]
    }
   ],
   "source": [
    "class Fibs:\n",
    "    def __init__(self, n=10):\n",
    "        self.a = 0\n",
    "        self.b = 1\n",
    "        self.n = n\n",
    "\n",
    "    def __iter__(self):\n",
    "        return self\n",
    "\n",
    "    def __next__(self):\n",
    "        self.a, self.b = self.b, self.a + self.b\n",
    "        if self.a > self.n:\n",
    "            raise StopIteration\n",
    "        return self.a\n",
    "\n",
    "\n",
    "fibs = Fibs(100)\n",
    "for each in fibs:\n",
    "    print(each, end=' ')\n",
    "\n",
    "# 1 1 2 3 5 8 13 21 34 55 89"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c95b5df8-5160-45d0-8c1e-46eac4baa7c0",
   "metadata": {},
   "source": [
    "### 生成器\n",
    "\n",
    "- 在 Python 中，使用了 yield 的函数被称为生成器（generator）。\n",
    "- 跟普通函数不同的是，生成器是一个返回迭代器的函数，只能用于迭代操作，更简单点理解生成器就是一个迭代器。\n",
    "- 在调用生成器运行的过程中，每次遇到 yield 时函数会暂停并保存当前所有的运行信息，返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。\n",
    "- 调用一个生成器函数，返回的是一个迭代器对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "ec59913f-82d3-48b6-9a87-d410d9d68bdf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "生成器执行！\n",
      "1\n",
      "2\n",
      "生成器执行！\n",
      "1\n",
      "2\n"
     ]
    },
    {
     "ename": "StopIteration",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[71], line 17\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[38;5;66;03m# 生成器执行！\u001b[39;00m\n\u001b[0;32m     14\u001b[0m \u001b[38;5;66;03m# 1\u001b[39;00m\n\u001b[0;32m     16\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28mnext\u001b[39m(myG))  \u001b[38;5;66;03m# 2\u001b[39;00m\n\u001b[1;32m---> 17\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;28;43mnext\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mmyG\u001b[49m\u001b[43m)\u001b[49m)  \u001b[38;5;66;03m# StopIteration\u001b[39;00m\n",
      "\u001b[1;31mStopIteration\u001b[0m: "
     ]
    }
   ],
   "source": [
    "def myGen():\n",
    "    print('生成器执行！')\n",
    "    yield 1\n",
    "    yield 2\n",
    "    \n",
    "myG = myGen()\n",
    "for each in myG:\n",
    "    print(each)\n",
    "\n",
    "\n",
    "myG = myGen()\n",
    "print(next(myG))  \n",
    "# 生成器执行！\n",
    "# 1\n",
    "\n",
    "print(next(myG))  # 2\n",
    "print(next(myG))  # StopIteration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "6c1c5482-4da8-4124-8d69-3fca360ca35d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 1 2 3 5 8 13 21 34 55 89 "
     ]
    }
   ],
   "source": [
    "def libs(n):\n",
    "    a = 0\n",
    "    b = 1\n",
    "    while True:\n",
    "        a, b = b, a + b\n",
    "        if a > n:\n",
    "            return\n",
    "        yield a\n",
    "\n",
    "\n",
    "for each in libs(100):\n",
    "    print(each, end=' ')\n",
    "\n",
    "# 1 1 2 3 5 8 13 21 34 55 89"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "96baf77c-ba3a-4e8b-9387-81349c69589d",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
